package ppu

import (
	"fmt"
	"github.com/imacks/bitflags-go"
)

const (
	CR_NAME_TABLE_1            = 0b00000001
	CR_NAME_TABLE_2            = 0b00000010
	CR_VRAM_ADD_INCREMENT      = 0b00000100
	CR_SPRITE_PATTERN_ADDR     = 0b00001000
	CR_BACKGROUND_PATTERN_ADDR = 0b00010000
	CR_SPRITE_SIZE             = 0b00100000
	CR_MASTER_SLAVE_SELECT     = 0b01000000
	CR_GENERATE_NMI            = 0b10000000
)

type ControlRegister struct {
	Bits uint8
}

// NewControlRegister creates a new ControlRegister
func NewControlRegister() *ControlRegister {
	return &ControlRegister{
		Bits: 0,
	}
}

// NameTableAddr returns the address of the name table
func (cr *ControlRegister) NameTableAddr() uint16 {
	selectVal := cr.Bits & 0b11

	switch selectVal {
	case 0:
		return 0x2000
	case 1:
		return 0x2400
	case 2:
		return 0x2800
	case 3:
		return 0x2C00
	default:
		fmt.Println("Invalid name table select value")
		return 0x2000
	}
}

// VramAddrIncrement returns the increment value for the VRAM address
func (cr *ControlRegister) VramAddrIncrement() uint8 {
	if !bitflags.Has(cr.Bits, CR_VRAM_ADD_INCREMENT) {
		return 1
	}
	return 32
}

// SprtPatternAddr returns the address of the sprite pattern table
func (cr *ControlRegister) SprtPatternAddr() uint16 {
	if !bitflags.Has(cr.Bits, CR_SPRITE_PATTERN_ADDR) {
		return 0x0000
	}
	return 0x1000
}

// BkndPatternAddr returns the address of the background pattern table
func (cr *ControlRegister) BkndPatternAddr() uint16 {
	if !bitflags.Has(cr.Bits, CR_BACKGROUND_PATTERN_ADDR) {
		return 0x0000 // 0
	}
	return 0x1000
}

// SprtSize returns the size of the sprites
func (cr *ControlRegister) SprtSize() uint8 {
	if !bitflags.Has(cr.Bits, CR_SPRITE_SIZE) {
		return 8
	}
	return 16
}

// MasterSlaveSelect returns the master/slave select value
func (cr *ControlRegister) MasterSlaveSelect() uint8 {
	if !bitflags.Has(cr.Bits, CR_SPRITE_SIZE) {
		return 0
	}
	return 1
}

// GenerateVblankNMI returns the generate NMI value
func (cr *ControlRegister) GenerateVblankNMI() bool {
	return bitflags.Has(cr.Bits, CR_GENERATE_NMI)
}

// Update updates the control register with the given data
func (cr *ControlRegister) Update(data byte) {
	cr.Bits = data
}
